package com.disapand.strongarmy.service.impl

import cn.dev33.satoken.stp.*
import com.disapand.strongarmy.model.*
import com.disapand.strongarmy.service.*
import com.disapand.strongarmy.vo.*
import com.disapand.strongarmy.vo.menu.*
import org.ktorm.database.*
import org.ktorm.dsl.*
import org.ktorm.entity.*
import org.springframework.stereotype.*
import java.time.*
import kotlin.math.*


/**
 *
 * @auth disapand
 * @date 2021/11/5 - 20:36 - 星期五
 *
 */
@Service
class MenuServiceImpl(private val database: Database) : MenuService {

    /**
     * 新增菜单
     *
     * @param name
     * @param path
     * @param icon
     * @param parentId
     * @param weight
     * @return
     */
    override fun add(name: String, path: String?, icon: String?, parentId: Int, weight: Int): Boolean {
        return database.menus.add(Menu {
            this.name = name
            this.path = path ?: ""
            this.icon = icon ?: ""
            this.parentId = parentId
            this.weight = weight
            this.createdAt = LocalDateTime.now()
            this.createdBy = StpUtil.getLoginIdAsInt()
        }) > 0
    }

    /**
     * 编辑菜单
     *
     * @param id
     * @param name
     * @param path
     * @param icon
     * @param parentId
     * @param weight
     * @return
     */
    override fun edit(id: Int, name: String?, path: String?,
                      icon: String?, parentId: Int?, weight: Int?): Boolean {
        val menu = database.menus.find { it.id eq id } ?: return false
        if (name != null) {
            menu.name = name
        }
        if (path != null) {
            menu.path = path
        }
        if (icon == null) {
            menu.icon = ""
        }
        if (parentId == null) {
            menu.parentId = 0
        }
        if (weight != null) {
            menu.weight = weight
        }
        menu.updatedBy = StpUtil.getLoginIdAsInt()
        menu.updatedAt = LocalDateTime.now()
        val changes = menu.flushChanges()
        return changes > 0
    }

    /**
     * 获取所有的菜单
     *
     * @return
     */
    override fun get(): List<Menu> {
        return database.menus.filter { it.deleted eq false }.toList()
    }

    /**
     * 分页方式获取菜单
     *
     * @return
     */
    override fun get(
        name: String?,
        path: String?,
        parentId: Int?,
        status: Int?,
        createdBy: Int?,
        createdStartAt: LocalDateTime?,
        createdEndAt: LocalDateTime?,
        updatedBy: Int?,
        updatedStartAt: LocalDateTime?,
        updatedEndAt: LocalDateTime?,
        current: Int,
        pageSize: Int
    ): PageVO<MenuPageVO> {
        val menu = Menus.aliased("menu")
        val parentMenu = Menus.aliased("parent_menu")
        val createdAccount = Accounts.aliased("created")
        val updatedAccount = Accounts.aliased("updated")

        val query = database.from(menu)
            .leftJoin(parentMenu, on = menu.parentId eq parentMenu.id)
            .leftJoin(createdAccount, on = menu.createdBy eq createdAccount.id)
            .leftJoin(updatedAccount, on = menu.updatedBy eq updatedAccount.id)
            .select(
                menu.columns - menu.deleted
                        + parentMenu.name + createdAccount.username + updatedAccount.username
            )
            .where { menu.deleted eq false }
            .whereWithConditions {
                if (name != null) {
                    it += menu.name like "%name%"
                }

                if (path != null) {
                    it += menu.path like "%path%"
                }

                if (parentId != null) {
                    it += menu.parentId eq parentId
                }

                if (status != null) {
                    it += menu.status eq status
                }

                if (createdBy != null) {
                    it += menu.createdBy eq createdBy
                }

                if (createdStartAt != null && createdEndAt != null) {
                    it += menu.createdAt between createdStartAt..createdEndAt
                }

                if (createdStartAt != null && createdEndAt == null) {
                    it += menu.createdAt greaterEq createdStartAt
                }

                if (createdStartAt == null && createdEndAt != null) {
                    it += menu.createdAt lessEq createdEndAt
                }

                if (updatedBy != null) {
                    it += menu.updatedBy eq updatedBy
                }

                if (updatedStartAt != null && updatedEndAt != null) {
                    it += menu.updatedAt between updatedStartAt..updatedEndAt
                }

                if (updatedStartAt != null && updatedEndAt == null) {
                    it += menu.updatedAt greaterEq updatedStartAt
                }

                if (updatedStartAt == null && updatedEndAt != null) {
                    it += menu.updatedAt lessEq updatedEndAt
                }
            }
            .limit(pageSize * (current - 1), pageSize)

        val total = query.totalRecords
        val list = query.map { row ->
            MenuPageVO(
                id = row[menu.id],
                name = row[menu.name],
                path = row[menu.path],
                icon = row[menu.icon],
                parentId = row[menu.parentId],
                parentName = row[parentMenu.name],
                weight = row[menu.weight],
                status = row[menu.status],
                createdBy = row[menu.createdBy],
                createdByName = row[createdAccount.username],
                createdAt = row[menu.createdAt],
                updatedBy = row[menu.updatedBy],
                updatedByName = row[updatedAccount.username],
                updatedAt = row[menu.updatedAt]
            )
        }

        return PageVO(
            total,
            ceil(total.toDouble() / pageSize).toInt(),
            current,
            pageSize,
            list
        )
    }

    /**
     * 以 id 查询 menu
     *
     * @param id
     * @return
     */
    override fun get(id: Int): Menu? {
        return database.menus
            .find { (it.id eq id) and (it.deleted eq false) }
    }

    /**
     * 以 name 查询 menu
     *
     * @param name
     * @return
     */
    override fun get(name: String): List<Menu> {
        return database.menus
            .filter { it.name like "%$name%" }
            .filter { it.deleted eq false }
            .toList()
    }

    /**
     * 删除 menu
     *
     * @param ids
     * @return
     */
    override fun deleted(ids: IntArray): Boolean {
        database.batchUpdate(Menus) {
            for (id in ids) {
                item {
                    set(it.deleted, true)
                    set(it.updatedBy, StpUtil.getLoginIdAsInt())
                    set(it.updatedAt, LocalDateTime.now())
                    where {
                        it.id eq id
                    }
                }
            }
        }
        return true
    }
}